package main

import (
	"fmt"
	"os"
	"strconv"
	//m "math"
	"unicode"
)

type CharInfo struct {
	count int
	prev  []rune
	next  []rune
}

type WordInfo struct {
	count int
	prev  []rune
	next  []rune
}

// Is each of the rune in array is a Han Character.
func AllIsHanChar(word []rune, rangeTable *unicode.RangeTable) bool {
	count := len(word)
	for i := 0; i < count; i += 1 {
		if !unicode.Is(rangeTable, word[i]) {
			return false
		}
	}
	return true
}

func SameRunes(a, b []rune) bool {
	len := len(a)
	for i := 0; i < len; i++ {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}

// Seems no need.
func FindWord(word []rune, runelines [][]rune, ifrom int, jfrom int) int {
	result := 0
	wlen := len(word)
	count := len(runelines)
	for i := ifrom; i < count; i++ {
		runes := runelines[i]
		len := len(runes)
		for j := jfrom; j < len-wlen; j++ {
			slice := runes[j : j+wlen]
			if SameRunes(word, slice) {
				result++
			}
			//FindWord(word, runelines, i)
		}
		jfrom = 0

	}
	return result
}

func RecordHanCharInfo(runes []rune, dict1 map[rune]*CharInfo, rangeTable *unicode.RangeTable) {
	len := len(runes)
	for j := 0; j < len; j++ {
		ch := runes[j]
		if !unicode.Is(rangeTable, ch) {
			continue
		}

		ci := dict1[ch]
		if ci == nil {
			ci = new(CharInfo)
			dict1[ch] = ci
		}
		ci.count++

		if j > 0 {
			prev := runes[j-1]
			if unicode.Is(rangeTable, prev) {
				ci.prev = append(ci.prev, prev)
			}
		}

		if j < len-1 {
			next := runes[j+1]
			if unicode.Is(rangeTable, next) {
				ci.next = append(ci.next, next)
			}
		}

	}

}

func RecordHanWordInfo(runes []rune, dict2 map[string]*WordInfo, rangeTable *unicode.RangeTable) {
	wl := 2
	len := len(runes)
	for j := 0; j < len-wl; j++ {

		slice := runes[j : j+wl]
		if AllIsHanChar(slice, rangeTable) {

			word := string(slice)

			wi := dict2[word]
			if wi == nil {
				wi = new(WordInfo)
				dict2[word] = wi
			}
			wi.count++

			if j > 0 {
				hanch := runes[j-1]
				if unicode.Is(rangeTable, hanch) {
					wi.prev = append(wi.prev, runes[j-1])
				}
			}
			if j < len-wl {
				hanch := runes[j+wl]
				if unicode.Is(rangeTable, hanch) {
					wi.next = append(wi.next, runes[j+wl])
				}
			}
		}
	}

}

func Extract(runelines [][]rune, itvn *Intervene) (map[rune]*CharInfo, map[string]*WordInfo, int) {
	fmt.Println("=====")
	rangeTable := unicode.Scripts["Han"]
	lineCount := len(runelines)
	charCount := 0
	dict1 := map[rune]*CharInfo{}
	dict2 := map[string]*WordInfo{}

	for i := 0; i < lineCount; i++ {
		runes := runelines[i]
		len := len(runes)
		for i := 0; i < len; i++ {
			ch := runes[i]
			if unicode.Is(rangeTable, ch) {
				charCount++
			}
		}

		RecordHanCharInfo(runes, dict1, rangeTable)
		RecordHanWordInfo(runes, dict2, rangeTable)
	}

	/*
		fmt.Println("Dicts Length")
		fmt.Println(len(dict1))
		fmt.Println(len(dict2))
		fmt.Println(dict1['朕'].count)
		//fmt.Println(dict["黛玉"].count)
		//fmt.Println(dict["计算"].count)
		//fmt.Println(dict["机关"].count)
		fmt.Println(dict2["宝玉"].count)
		//fmt.Println(string(dict["宝玉"].next))
		//fmt.Println(string(dict["宝玉"].prev))
		fmt.Println("=====")
	*/
	return dict1, dict2, charCount
}

func Analyze(dict1 map[rune]*CharInfo, dict2 map[string]*WordInfo, charCount int) int {
	wordCount := len(dict2)

	// Count and group.
	// 0~9 0-10, 10-20...
	// presume one Han word appears 10000 times at most.
	// Max
	group := [1000]int{0}
	maxIndex := 0
	for _, wi := range dict2 {
		index := wi.count / 10
		group[index] += 1
		if index > maxIndex {
			maxIndex = index
		}
	}

	// Min
	percent := 0.001
	minIndex := 0
	remainCount := wordCount
	for i := 0; i <= maxIndex; i += 1 {
		remainCount = remainCount - group[i]

		if float64(remainCount)/float64(wordCount) < percent {
			minIndex = i
			break
		}
	}
	fmt.Println(minIndex, "~", maxIndex)

	////////////////////////////////////////////////////////////////////
	// HOW TO: threshold

	// Store the word maybe,.
	threshold := minIndex * 10
	f2w, err := os.Create("w.txt")
	if err != nil {
		defer f2w.Close()
	}
	// The Han word appears most times.
	minRepeat := 200
	for word, wi := range dict2 {
		if wi.count < minRepeat {
			continue
		}
		if wi.count >= threshold {
			// 

			p := ProcessEntropy(word, dict1, dict2, charCount)

			pstr := strconv.FormatFloat(p, 'f', -1, 32)
			f2w.WriteString(word + ": " + pstr + "\r\n")
		}
	}
	//fmt.Println(group)
	return 0
}

func ProcessEntropy(word string, dict1 map[rune]*CharInfo, dict2 map[string]*WordInfo, charCount int) float64 {

	wi := dict2[word]
	charCountf := float64(charCount)
	if wi != nil {
		count := wi.count
		wordProb := float64(count) / charCountf

		runes := []rune(word)
		ci1 := dict1[runes[0]]
		ci2 := dict1[runes[1]]
		char1Prob := float64(ci1.count) / charCountf
		char2Prob := float64(ci2.count) / charCountf
		return char1Prob * char2Prob / wordProb
	}
	return 0.0
}
